<?php
/**
 * Работа с файлами
 * 
 * Класс для работы с файлами
 * @author Anton Zavidov
 * @package myLiveShop
 */

/**
 * Базовый класс для работы с файлами
 *
 */
class File extends Base{
	//константа для дописывания в конец файла
	const APPEND="append";
	//дописывание в начало файла
	const PREPEND="prepend";
	//перезапись файла
	const REWRITE="rewrite";
	//обработка файла
	const CALLBACK="callback";
	/**
	 * Инстанс класа
	 *
	 * @var File
	 */
	private static $instance;

	public function __construct(){
		parent::__construct(__CLASS__);
	}
	/**
	 * Поличение инстанса класса
	 *
	 * @return File
	 */
	private static function getInstance() {
		if (self::$instance === null)
		return self::$instance = new self();
		else
		return self::$instance;
	}
	/**
	 * Базовая функция
	 * 
	 * Если указано $value то записываем если нет то читаем
	 * В $params можем передать режим записи mode= File::PREPEND, File::APPEND, FILE::CALLBACK или File::REWRITE(по умолчанию)
	 * при mode=File::CALLBACK обязательно должен быть ещё дополнительный параметр callback который может быть массивом array(class,method) либо строкой function
	 * callback функция должна принимать один строковой параметр и возвращать строковое значение которое потом будет записанно в файл
	 * если естановлен параметр add то значит файл обязательно должен уже существовать
	 * Если не указать никаких параметров то цункция вернёт инстанс
	 *
	 * @param string $name имя файла
	 * @param string $value содержимое для записи
	 * @param array $params mode=File::PREPEND | File::APPEND | FILE::CALLBACK | File::REWRITE, [callback=function | array(class,method)], [add=true] режим записи
	 * @return mixed true/false зри записи или содержимое файла при чтении
	 */
	public static function _($name=null,$value=null,$params=array()){
		//возвращает инстанс ели ничего не переданно
		if(!$name && !$value)return self::getInstance();
		//возвращает ошибку если не указанно имя файла
		if(!$name){
			new CoreExeption('Не указано имя файла для '.($value===null?"чтения":"записи"),E_ERROR,__FILE__,__LINE__);
			return false;
		}
		//если нет данных то читаем иначе пишем
		if($value===null && (!isset($params['mode']) || (isset($params['mode']) && $params['mode']!=self::CALLBACK))){
			return self::get($name,$params);
		}else{
			return self::set($name,$value,$params);
		}
	}
	/**
	 * Проверка на существование файла
	 *
	 * @param string $name имя файла
	 * @return boolean true если файл существует, false если нет
	 */
	public static function exists($name=null){
		//возвращает ошибку если не указанно имя файла
		if(!$name){
			new CoreExeption('Не указано имя файла для проверки',E_ERROR,__FILE__,__LINE__);
			return null;
		}
		return file_exists(Config::_('path_file').FS.$name);
	}
	/**
	 * Проверка на записываемость файла
	 *
	 * @param string $name имя файла
	 * @return boolean true если файл доступен для записи, false если нет
	 */
	public static function writable($name=null){
		//возвращает ошибку если не указанно имя файла
		if(!$name){
			new CoreExeption('Не указано имя файла для проверки',E_ERROR,__FILE__,__LINE__);
			return null;
		}
		if(!file_exists(Config::_('path_file').FS.$name)){
			new CoreExeption('Не возможно проверить файл '.$name.' так как он несуществует',E_WARNING,__FILE__,__LINE__);
			return null;
		}
		return is_writable(Config::_('path_file').FS.$name);
	}
	/**
	 * Удаление файла
	 *
	 * @param string $name имя файла
	 * @return boolean true если файл удалён успешно, false если нет
	 */
	public static function delete($name=null){
		//возвращает ошибку если не указанно имя файла
		if(!$name){
			new CoreExeption('Не указано имя файла для удаления',E_ERROR,__FILE__,__LINE__);
			return false;
		}
		if(!file_exists(Config::_('path_file').FS.$name)){
			new CoreExeption('Не возможно удалить файл '.$name.' так как он несуществует',E_WARNING,__FILE__,__LINE__);
			return false;
		}
		return unlink(Config::_('path_file').FS.$name);
	}
	/**
	 * Создание пустого файла
	 *
	 * @param string $name имя файла
	 * @return boolean true если файл создан успешно, false если нет
	 */
	public static function create($name=null){
		//возвращает ошибку если не указанно имя файла
		if(!$name){
			new CoreExeption('Не указано имя файла для создания',E_ERROR,__FILE__,__LINE__);
			return false;
		}
		return self::set($name,"",array('add'=>true));
	}
	/**
	 * Читаем файл
	 *
	 * @param class $self инстанс
	 * @param array $params параметры чтения (пока не используется)
	 * @return string содержимое файла
	 */
	private static function get($name,$params){
		if(!file_exists(Config::_('path_file').FS.$name)){
			new CoreExeption('Не возможно прочитать файл '.$name.' так как он несуществует',E_WARNING,__FILE__,__LINE__);
			return false;
		}
		L('Прочитан файл '.$name);
		return file_get_contents(Config::_('path_file').FS.$name);
	}
	/**
	 * Записываем в файл
	 * 
	 * В $params можем передать режим записи mode= File::PREPEND, File::APPEND, FILE::CALLBACK или File::REWRITE(по умолчанию)
	 * при mode=File::CALLBACK обязательно должен быть ещё дополнительный параметр callback который может быть массивом array(class,method) либо строкой function
	 * callback функция должна принимать один строковой параметр и возвращать строковое значение которое потом будет записанно в файл
	 * если естановлен параметр add то значит файл обязательно должен уже существовать
	 *
	 * @param class $self инстанс
	 * @param string $value данные для записи
	 * @param array $params mode=File::PREPEND | File::APPEND | FILE::CALLBACK | File::REWRITE, [callback=function | array(class,method)], [add=true] режим записи
	 * @return boolean true - если запись произошла успешно, false - если нет
	 */
	private static function set($name,$value=null,$params=false){
		//проверяем на существовании файла  если установлен параметр add
		if(!isset($params['add']) && !file_exists($name)){
			new CoreExeption('Невозможно записать в файл '.$name." так как он не существует",E_WARNING,__FILE__,__LINE__);
			return false;
		}
		//устанавливаем режим записи по умолчанию File::REWRITE если он не был установлен
		if(!isset($params['mode']))$mode=File::REWRITE;
		else $mode=$params['mode'];
		//устанавливаем режим записи по умолчанию File::CALLBACK если переданна callbsack функция
		if(isset($params['callback']))$mode=File::CALLBACK;
		//если нет callback функции но стоит режим записи File::CALLBACK то кидаем исключение
		if($mode==File::CALLBACK && !isset($params['callback'])){
			new CoreExeption('Невозможно обработать файл '.$name." так как не указан callback в параметрах",E_WARNING,__FILE__,__LINE__,$params);
			return false;
		}
		switch ($mode) {
			case File::APPEND:
				$open_mode="a+";
				break;
			case File::PREPEND:
				$open_mode="w";
				//в режимах File::PREPEND(запись в начало файла) или File::CALLBACK(обработка файла) получаем содержимое файла
				$file=self::get($name,null);
				break;
			case File::CALLBACK:
				$open_mode="w";
				//в режимах File::PREPEND(запись в начало файла) или File::CALLBACK(обработка файла) получаем содержимое файла
				$file=self::get($name,null);
				break;
			default:
				$open_mode='w';
				break;
		}
		//пытаемся открыть файл
		if(!$fo=fopen($name,$open_mode)){
			new CoreExeption('Не удаётся открыть файл '.$name." на запись",E_WARNING,__FILE__,__LINE__,$params);
			return false;
		}
		//в режиме File::PREPEND добавляем строки в начало файла
		if($mode==File::PREPEND){
			$value.=$file;
		}
		//в режиме File::CALLBACK запускаем callback функцию для обработки файла
		if($mode==File::CALLBACK){
			if(is_array($params['callback'])){
				if(!method_exists($params['callback'][0],$params['callback'][1])){
					new CoreExeption('Невозможно обработать файл '.$name." так как не указаный callback ".$params['callback'][0].'::'.$params['callback'][1].' не работает',E_WARNING,__FILE__,__LINE__,$params);
					return false;
				}
				L('Вызван обработчик файла для '.$name.' '.$params['callback'][0].'::'.$params['callback'][1]);
				$value=call_user_func(array($params['callback'][0],$params['callback'][1]),$file);
			}else{
				$func=$params['callback'];
				L('Вызван обработчик файла для '.$name.' '.$func);
				$value=$func($file);
			}
		}
		//пытаемся записать данные
		if (fwrite($fo, $value) === FALSE) {
			new CoreExeption('Невозможно записать в файл '.$name,E_WARNING,__FILE__,__LINE__,$params);
			return false;
		}
		fclose($fo);
		L('Записан файл '.$name);
		return true;
	}
	/**
	 * Обработка файла при помощи функции
	 *
	 * @param string $name имя файла
	 * @param string $function имя функции или метода для обработки
	 * @param string $class имя класса в котором метод обработки
	 * @return boolean true/false результат записи
	 */
	public static function processing($name,$function,$class=null){
		return File::_($name,"",array("callback"=>($class?array($class,$function):$function)));
	}
}